﻿using System;
using System.Windows.Forms;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IsreversI.GUI
{
    class BoardControl : UserControl
    {
        #region member variables
        #region GUI elements
        private BoardTileControl[,] tiles;
        private Label[] xLabels;
        private Label[] yLabels;
        #endregion

        Visualisation.BoardVisualView visual;
        GameLogic.GameStateController stateController;
        Size padding = new Size(24, 24);
        #endregion

        #region events
        #endregion

        #region properties
        public Size BoardSize
        {
            get
            {
                return visual.Size;
            }
        }

        public bool EnableDecoration
        {
            get
            {
                return this.visual.EnableDecoration;
            }
            set
            {
                this.visual.EnableDecoration = value;
            }
        }
        #endregion

        #region constructors
        public BoardControl(Visualisation.BoardVisualView visual, GameLogic.GameStateController stateController)
        {
            this.visual = visual;
            this.stateController = stateController;

            this.Initialize();
            this.handleModelChange(this, EventArgs.Empty);
        }

        public BoardControl(GameLogic.BoardModel model)
        {
            this.visual = new Visualisation.BoardVisualView(model);
            this.stateController = new GameLogic.GameStateController(model);

            this.Initialize();
        }

        private void Initialize()
        {
            // Safe to add both of the below events, as the board checks that there really was a change.
            this.visual.PreBoardModelChanged += this.stateController.acceptNewModel;
            this.stateController.PreBoardModelChanged += this.visual.acceptNewModel;
            this.visual.NewBoardInPlace += this.handleModelChange;

            this.AutoSize = false;
            this.Resize += this.handleResize;
        }
        #endregion

        #region event handlers
        private void handleResize(object Sender, EventArgs ea)
        {
            if (this.tiles == null)
                return;
            Size boardSize = this.Size - this.padding;
            Point boardLocation = new Point(this.padding.Width, this.padding.Height);
            int xStep = boardSize.Width / tiles.GetLength(0);
            int yStep = boardSize.Height / tiles.GetLength(1);
            Size xCoordLabelDefaultSize = new Size(xStep < 24 ? xStep : 24, 12); // Correction for small sizes.
            Size yCoordLabelDefaultSize = new Size(24, 12);
            for (int xCounter = 0; xCounter < tiles.GetLength(0); ++xCounter)
                for (int yCounter = 0; yCounter < tiles.GetLength(1); ++yCounter)
                {
                    this.tiles[xCounter, yCounter].Size = new Size(xStep, yStep);
                    this.tiles[xCounter, yCounter].Location = new Point(boardLocation.X + xStep * xCounter,boardLocation.Y + yStep * yCounter);

                    if (xCounter == 0)
                    {
                        this.yLabels[yCounter].Location = new Point(0, boardLocation.Y + yStep * yCounter + yStep / 2 - 6);
                        this.yLabels[yCounter].Size = yCoordLabelDefaultSize;
                    }
                    if (yCounter == 0)
                    {
                        this.xLabels[xCounter].Location = new Point(boardLocation.X + xStep * xCounter + xStep / 2 - 6, 0);
                        this.xLabels[xCounter].Size = xCoordLabelDefaultSize;
                    }
                }
        }

        private void handleModelChange(object sender, EventArgs ea)
        {
            //Removes the old tiles & labels
            if (this.tiles != null)
                for (int a = 0; a < tiles.GetLength(0); ++a)
                    for (int b = 0; b < tiles.GetLength(1); ++b)
                    {
                        this.Controls.Remove(this.tiles[a, b]);
                        if (a == 0)
                            this.Controls.Remove(this.yLabels[b]);
                        if (b == 0)
                            this.Controls.Remove(this.xLabels[a]);
                    }

            this.tiles = new BoardTileControl[this.BoardSize.Width, this.BoardSize.Height];
            this.xLabels = new Label[this.BoardSize.Width];
            this.yLabels = new Label[this.BoardSize.Height];

            for (int xCounter = 0; xCounter < tiles.GetLength(0); ++xCounter)
                for (int yCounter = 0; yCounter < tiles.GetLength(1); ++yCounter)
                {
                    BoardTileControl temptile = new BoardTileControl(this.visual, this.stateController, new Point(xCounter, yCounter));
                    temptile.BackColor = (xCounter + yCounter) % 2 == 0 ? SystemColors.ControlLightLight : SystemColors.ControlLight;

                    this.tiles[xCounter, yCounter] = temptile;
                    this.Controls.Add(temptile);

                    if (xCounter == 0)
                    {
                        Label tempYLabel = new Label();
                        tempYLabel.Text = (yCounter + 1).ToString();
                        tempYLabel.ForeColor = SystemColors.ControlDarkDark;
                        this.yLabels[yCounter] = tempYLabel;
                        this.Controls.Add(tempYLabel);
                    }
                    if (yCounter == 0)
                    {
                        Label tempXLabel = new Label();
                        tempXLabel.Text = ((char)(xCounter + 'A')).ToString();
                        tempXLabel.ForeColor = SystemColors.ControlDarkDark;
                        this.xLabels[xCounter] = tempXLabel;
                        this.Controls.Add(tempXLabel);
                    }

                }
            this.handleResize(this, ea);
        }
        #endregion

        #region public methods
        #endregion

        #region private methods
        #endregion
    }
}
